/*
 * Copyright 2019-2025 the original author or authors.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * https://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.iiifi.kite.core.convert;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.springframework.cglib.core.Converter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;

import com.iiifi.kite.core.function.CheckedFunction;
import com.iiifi.kite.core.util.ClassUtils;
import com.iiifi.kite.core.util.ConvertUtils;
import com.iiifi.kite.core.util.ReflectUtils;
import com.iiifi.kite.core.util.Unchecked;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 组合 spring cglib Converter 和 spring ConversionService
 *
 * @author kite@iiifi.com 花朝
 */
@Slf4j
@AllArgsConstructor
public class KiteConverter implements Converter {
    private static final ConcurrentMap<String, TypeDescriptor> TYPE_CACHE = new ConcurrentHashMap<>();
    private final Class<?> sourceClazz;
    private final Class<?> targetClazz;

    /**
     * cglib convert
     *
     * @param value 源对象属性
     * @param target 目标对象属性类
     * @param fieldName 目标的field名，原为 set 方法名，MicaBeanCopier 里做了更改
     * @return {Object}
     */
    @Override
    @Nullable
    public Object convert(@Nullable Object value, Class target, final Object fieldName) {
        if (value == null) {
            return null;
        }
        // 类型一样，不需要转换
        if (ClassUtils.isAssignableValue(target, value)) {
            return value;
        }
        try {
            TypeDescriptor targetDescriptor = KiteConverter.getTypeDescriptor(targetClazz, (String) fieldName);
            // 1. 判断 sourceClazz 为 Map
            if (Map.class.isAssignableFrom(sourceClazz)) {
                return ConvertUtils.convert(value, targetDescriptor);
            } else {
                TypeDescriptor sourceDescriptor = KiteConverter.getTypeDescriptor(sourceClazz, (String) fieldName);
                return ConvertUtils.convert(value, sourceDescriptor, targetDescriptor);
            }
        } catch (Throwable e) {
            log.warn("MicaConverter error", e);
            return null;
        }
    }

    private static TypeDescriptor getTypeDescriptor(final Class<?> clazz, final String fieldName) {
        String srcCacheKey = clazz.getName() + fieldName;
        // 忽略抛出异常的函数，定义完整泛型，避免编译问题
        CheckedFunction<String, TypeDescriptor> uncheckedFunction = (key) -> {
            // 这里 property 理论上不会为 null
            Field field = ReflectUtils.getField(clazz, fieldName);
            if (field == null) {
                throw new NoSuchFieldException(fieldName);
            }
            return new TypeDescriptor(field);
        };
        return TYPE_CACHE.computeIfAbsent(srcCacheKey, Unchecked.function(uncheckedFunction));
    }
}
